package com.rickpan.controller;

import com.rickpan.dto.share.ShareAccessRequest;
import com.rickpan.dto.share.ShareAccessResponse;
import com.rickpan.dto.share.ShareResponse;
import com.rickpan.entity.FileInfo;
import com.rickpan.repository.FileInfoRepository;
import com.rickpan.dto.common.ApiResponse;
import com.rickpan.service.FileShareService;
import com.rickpan.service.ShareSecurityService;
import com.rickpan.service.FileManagementService;
import com.rickpan.service.FileStorageService;
import com.rickpan.storage.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 分享访问控制器 (无需登录)
 * 
 * @author RickPan Team
 * @since 2025-01-05
 */
@RestController
@RequestMapping("/api/shares")
public class ShareAccessController {

    private static final Logger log = LoggerFactory.getLogger(ShareAccessController.class);

    @Autowired
    private FileShareService fileShareService;

    @Autowired
    private ShareSecurityService shareSecurityService;

    @Autowired
    private FileManagementService fileManagementService;

    @Autowired
    private FileInfoRepository fileInfoRepository;

    @Autowired
    private StorageService storageService;

    @Autowired
    private FileStorageService fileStorageService;

    /**
     * 获取分享信息 (公开接口)
     * GET /api/shares/{shareCode}/info
     */
    @GetMapping("/{shareCode}/info")
    public ResponseEntity<ApiResponse<ShareInfoResponse>> getShareInfo(@PathVariable String shareCode) {
        try {
            log.info("获取分享信息: shareCode={}", shareCode);

            ShareResponse shareResponse = fileShareService.getShareInfo(shareCode);
            
            // 构建公开的分享信息 (不包含敏感信息)
            ShareInfoResponse response = new ShareInfoResponse();
            response.setShareCode(shareResponse.getShareCode());
            response.setFileName(shareResponse.getFileName());
            response.setFileSize(shareResponse.getFileSize());
            response.setShareType(shareResponse.getShareType().toString());
            response.setAllowPreview(shareResponse.getAllowPreview());
            response.setAllowDownload(shareResponse.getAllowDownload());
            response.setSharerName(shareResponse.getUserName());
            response.setExpired(shareResponse.getExpired());
            
            return ResponseEntity.ok(ApiResponse.success(response));
            
        } catch (Exception e) {
            log.error("获取分享信息失败: shareCode={}", shareCode, e);
            return ResponseEntity.badRequest()
                    .body(ApiResponse.error("获取分享信息失败: " + e.getMessage()));
        }
    }

    /**
     * 访问分享文件
     * POST /api/shares/{shareCode}/access
     */
    @PostMapping("/{shareCode}/access")
    public ResponseEntity<ApiResponse<ShareAccessResponse>> accessShare(
            @PathVariable String shareCode,
            @RequestBody ShareAccessRequest request,
            HttpServletRequest httpRequest) {
        
        try {
            log.info("访问分享文件: shareCode={}, action={}", shareCode, request.getAction());

            ShareAccessResponse response = shareSecurityService.validateAccess(shareCode, request, httpRequest);
            
            if (response.getAllowed()) {
                return ResponseEntity.ok(ApiResponse.success("访问成功", response));
            } else {
                return ResponseEntity.badRequest()
                        .body(ApiResponse.error(response.getErrorMessage()));
            }
            
        } catch (Exception e) {
            log.error("访问分享文件失败: shareCode={}", shareCode, e);
            return ResponseEntity.badRequest()
                    .body(ApiResponse.error("访问失败: " + e.getMessage()));
        }
    }

    /**
     * 下载分享文件
     * GET /api/shares/{shareCode}/download?token={accessToken}
     */
    @GetMapping("/{shareCode}/download")
    public ResponseEntity<Resource> downloadSharedFile(
            @PathVariable String shareCode,
            @RequestParam String token) {
        
        try {
            log.info("下载分享文件: shareCode={}", shareCode);

            // 验证访问令牌
            String validatedShareCode = shareSecurityService.validateAccessToken(token);
            if (!shareCode.equals(validatedShareCode)) {
                return ResponseEntity.badRequest().build();
            }

            // 获取分享信息
            ShareResponse shareResponse = fileShareService.getShareInfo(shareCode);
            if (!shareResponse.getAllowDownload()) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
            }

            // 获取文件信息
            FileInfo fileInfo = fileInfoRepository.findById(shareResponse.getFileId())
                    .orElseThrow(() -> new RuntimeException("文件不存在"));

            // 通过存储服务下载文件
            return downloadFileFromStorage(fileInfo);
            
        } catch (Exception e) {
            log.error("下载分享文件失败: shareCode={}", shareCode, e);
            return ResponseEntity.badRequest().build();
        }
    }

    /**
     * 预览分享文件
     * GET /api/shares/{shareCode}/preview?token={accessToken}
     */
    @GetMapping("/{shareCode}/preview")
    public ResponseEntity<Resource> previewSharedFile(
            @PathVariable String shareCode,
            @RequestParam String token) {
        
        try {
            log.info("预览分享文件: shareCode={}", shareCode);

            // 验证访问令牌
            String validatedShareCode = shareSecurityService.validateAccessToken(token);
            if (!shareCode.equals(validatedShareCode)) {
                return ResponseEntity.badRequest().build();
            }

            // 获取分享信息
            ShareResponse shareResponse = fileShareService.getShareInfo(shareCode);
            if (!shareResponse.getAllowPreview()) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
            }

            // 获取文件信息
            FileInfo fileInfo = fileInfoRepository.findById(shareResponse.getFileId())
                    .orElseThrow(() -> new RuntimeException("文件不存在"));

            // 通过存储服务预览文件 (复用下载逻辑)
            return downloadFileFromStorage(fileInfo);
            
        } catch (Exception e) {
            log.error("预览分享文件失败: shareCode={}", shareCode, e);
            return ResponseEntity.badRequest().build();
        }
    }

    /**
     * 分享信息响应DTO (公开信息)
     */
    public static class ShareInfoResponse {
        private String shareCode;
        private String fileName;
        private Long fileSize;
        private String shareType;
        private Boolean allowPreview;
        private Boolean allowDownload;
        private String sharerName;
        private Boolean expired;

        public ShareInfoResponse() {}

        public String getShareCode() { return shareCode; }
        public void setShareCode(String shareCode) { this.shareCode = shareCode; }

        public String getFileName() { return fileName; }
        public void setFileName(String fileName) { this.fileName = fileName; }

        public Long getFileSize() { return fileSize; }
        public void setFileSize(Long fileSize) { this.fileSize = fileSize; }

        public String getShareType() { return shareType; }
        public void setShareType(String shareType) { this.shareType = shareType; }

        public Boolean getAllowPreview() { return allowPreview; }
        public void setAllowPreview(Boolean allowPreview) { this.allowPreview = allowPreview; }

        public Boolean getAllowDownload() { return allowDownload; }
        public void setAllowDownload(Boolean allowDownload) { this.allowDownload = allowDownload; }

        public String getSharerName() { return sharerName; }
        public void setSharerName(String sharerName) { this.sharerName = sharerName; }

        public Boolean getExpired() { return expired; }
        public void setExpired(Boolean expired) { this.expired = expired; }
    }

    /**
     * 从存储服务下载文件
     */
    private ResponseEntity<Resource> downloadFileFromStorage(FileInfo fileInfo) {
        try {
            // 检查文件是否在 MinIO 中存在
            boolean existsInMinIO = false;
            if ("minio".equals(storageService.getStorageType())) {
                try {
                    existsInMinIO = storageService.fileExists(fileInfo.getFilePath());
                } catch (Exception e) {
                    log.warn("检查MinIO文件存在性失败: {}", fileInfo.getFilePath(), e);
                }
            }

            if (existsInMinIO) {
                // 从 MinIO 代理下载，确保使用正确的文件名
                return proxyDownloadFromMinIO(fileInfo);
            } else {
                // 从本地存储读取文件
                Path localFilePath = fileStorageService.getAbsolutePath(fileInfo.getFilePath());
                if (!Files.exists(localFilePath)) {
                    return ResponseEntity.notFound().build();
                }

                Resource resource = new InputStreamResource(new FileInputStream(localFilePath.toFile()));

                // 设置响应头
                String encodedFilename = URLEncoder.encode(fileInfo.getOriginalName(), StandardCharsets.UTF_8)
                        .replaceAll("\\+", "%20");

                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_DISPOSITION,
                               "attachment; filename=\"" + fileInfo.getOriginalName() + "\"; filename*=UTF-8''" + encodedFilename)
                        .header(HttpHeaders.CONTENT_TYPE,
                               fileInfo.getMimeType() != null ? fileInfo.getMimeType() : MediaType.APPLICATION_OCTET_STREAM_VALUE)
                        .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileInfo.getFileSize()))
                        .body(resource);
            }
        } catch (Exception e) {
            log.error("下载文件失败: fileId={}", fileInfo.getId(), e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 从MinIO代理下载文件，确保使用正确的文件名
     */
    private ResponseEntity<Resource> proxyDownloadFromMinIO(FileInfo fileInfo) {
        try {
            // 生成MinIO临时下载URL
            String downloadUrl = storageService.generateDownloadUrl(
                fileInfo.getFilePath(),
                java.time.Duration.ofMinutes(5)
            );

            log.info("代理下载MinIO文件: fileId={}, url={}", fileInfo.getId(), downloadUrl);

            // 从MinIO URL获取文件流
            URL url = new URL(downloadUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(30000);

            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                log.error("MinIO下载失败: responseCode={}", responseCode);
                return ResponseEntity.notFound().build();
            }

            // 获取文件流
            InputStream inputStream = connection.getInputStream();
            Resource resource = new InputStreamResource(inputStream);

            // 设置正确的文件名
            String encodedFilename = URLEncoder.encode(fileInfo.getOriginalName(), StandardCharsets.UTF_8)
                    .replaceAll("\\+", "%20");

            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION,
                           "attachment; filename=\"" + fileInfo.getOriginalName() + "\"; filename*=UTF-8''" + encodedFilename)
                    .header(HttpHeaders.CONTENT_TYPE,
                           fileInfo.getMimeType() != null ? fileInfo.getMimeType() : MediaType.APPLICATION_OCTET_STREAM_VALUE)
                    .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileInfo.getFileSize()))
                    .body(resource);

        } catch (Exception e) {
            log.error("MinIO代理下载失败: fileId={}", fileInfo.getId(), e);
            return ResponseEntity.internalServerError().build();
        }
    }
}
